Aggregate 2 sources
We take berlin weather from station in Schoenefeld with id =
10384
Rows: 24422 Columns: 11── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl (10): X2, X3, X4, X5, X6, X7, X8, X9, X10, X11
date (1): X1
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# think about duration of description column
# Kelheim
weatherstack_kelheim_daily = weatherstack_kelheim %>%
group_by(date) %>%
summarize(description = description,precip_day = sum(precip),visibility_mean = mean(visibility),totalsnow_daily = mean(totalsnow_daily))
`summarise()` has grouped output by 'date'. You can override using the `.groups` argument.
weatherstack_kelheim_weekly = weatherstack_kelheim_daily %>%
mutate(year_week = paste0(isoyear(date),"-",isoweek(date))) %>%
group_by(year_week) %>%
summarize(description = description,date = first(date), precip_week = sum(precip_day),visibility_mean = mean(visibility_mean),totalsnow_weekly =sum( totalsnow_daily))
`summarise()` has grouped output by 'year_week'. You can override using the `.groups` argument.
weatherstack_kelheim_weekly = unique(weatherstack_kelheim_weekly)
print(weatherstack_kelheim_weekly)
#Berlin
berlin_weather_weekly = berlin_weather_daily %>% filter(year(date) >=2020) %>%
mutate(year_week = paste0(isoyear(date),"-",isoweek(date))) %>%
group_by(year_week) %>%
summarize(date = first(date), prcp_week = sum(prcp), tavg= mean(tavg),snow_week =sum( snow),wspd = mean(wspd),tmax = max(tmax)) %>%
arrange(year_week)
print(berlin_weather_weekly)
#mob_joined = rbind(snz_mobility_kelheim,bavaria_mobility)
#Kelheim
snz_mobility_kelheim_year_week = snz_mobility_kelheim %>%
mutate(year_week = paste0(isoyear(date),"-",isoweek(date))) %>%
group_by(year_week) %>%
summarize(date = first(date),not_at_home_change = mean(not_at_home_change))
mob_joined_with_weather_kelheim = snz_mobility_kelheim_year_week %>% inner_join(weatherstack_kelheim_weekly, by = "year_week") %>% select(-date.y) %>% rename(date = date.x)
print(mob_joined_with_weather_kelheim)
#Berlin
snz_mobility_berlin_year_week = snz_mobility_berlin %>%
mutate(year_week = paste0(isoyear(date),"-",isoweek(date))) %>%
group_by(year_week) %>%
summarize(date = first(date),not_at_home_change = mean(not_at_home_change))
mob_joined_with_weather_berlin = snz_mobility_berlin_year_week %>% inner_join(berlin_weather_weekly, by = "year_week") %>% select(-date.y) %>% rename(date = date.x)
print(mob_joined_with_weather_berlin)
#First plot with colour as precipitation
shapes <- c("Berlin" = 5, "Kelheim" = 3)
plt_color = ggplot()+
geom_point(data = mob_joined_with_weather_kelheim,aes(x = date,y = not_at_home_change,colour = precip_week,shape = "Kelheim"))+
#geom_point(data = mob_joined_with_weather_berlin,aes(x = date,y = not_at_home_change,colour = prcp_week,shape = "Berlin"))+
scale_color_gradient2()+
scale_shape_manual(values = shapes)
ggplotly(plt_color)
#Second plot as another line as precipitation
plt_line = ggplot(mob_joined_with_weather_kelheim)+
geom_point(aes(x = date,y = not_at_home_change))+
geom_line(aes(x = date,y = precip_week*0.5,color = "red"))
ggplotly(plt_line)
plt_hist_precip = ggplot(mob_joined_with_weather_kelheim,aes(x = precip_week,y = not_at_home_change))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 2,fill = "blue")
ggplotly(plt_hist_precip)
plt_hist_visibility = ggplot(mob_joined_with_weather_kelheim,aes(x = visibility_mean,y = not_at_home_change))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 0.5,fill = "blue")
ggplotly(plt_hist_visibility)
plt_hist_totalsnow = ggplot(mob_joined_with_weather_kelheim,aes(x = totalsnow_weekly,y = not_at_home_change))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 7,fill = "blue")
ggplotly(plt_hist_totalsnow)
#this is a bad plot because it takes description of 1 day of the week
plt_hist_descr = ggplot(mob_joined_with_weather_kelheim,aes(x = description,y = not_at_home_change))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 5,fill = "blue")+
coord_flip()
ggplotly(plt_hist_descr)
Let’s try it out with meteostat data, that contains scope of the
2022 without restictions
Ingolstadt data from id = 10860 station
ingolstadt_weather = read_delim("https://bulk.meteostat.net/v2/daily/10860.csv.gz",",",col_names = FALSE)
Rows: 19288 Columns: 11── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl (9): X2, X3, X4, X5, X6, X7, X8, X9, X10
lgl (1): X11
date (1): X1
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
colnames(ingolstadt_weather) = c("date", "tavg", "tmin", "tmax", "prcp", "snow", "wdir", "wspd", "wpgt", "pres", "tsun")
# We don't need data of weather before 2020, because of snz_mobility date, also data isn't precise
ingolstadt_weather = ingolstadt_weather %>% filter(year(date)>=2020)%>% replace_na(list(snow = 0))
print(ingolstadt_weather)
Hohenfels data from id = 10775 station
hohenfels_weather = read_delim("https://bulk.meteostat.net/v2/daily/10775.csv.gz",",",col_names = FALSE)
Rows: 6311 Columns: 11── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl (8): X2, X3, X4, X5, X6, X7, X8, X10
lgl (2): X9, X11
date (1): X1
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
colnames(hohenfels_weather) = c("date", "tavg", "tmin", "tmax", "prcp", "snow", "wdir", "wspd", "wpgt", "pres", "tsun")
# We don't need data of weather before 2020, because of snz_mobility date, also data isn't precise
hohenfels_weather = hohenfels_weather %>% filter(year(date)>=2020) %>% replace_na(list(snow = 0))
print(hohenfels_weather)
As we can see in Hohenfels data isn’t that accurate and precipitation
is data is missing fr year 2020, so for the further analysis we take
only Ingolstadt data.
ingolstadt_weather_weekly = ingolstadt_weather %>%
mutate(year_week = paste0(isoyear(date),"-",isoweek(date))) %>%
group_by(year_week) %>%
summarize(date = first(date), prcp_week = sum(prcp), tavg= mean(tavg),snow_week =sum( snow),wspd = mean(wspd),tmax = max(tmax)) %>%
arrange(year_week)
#ingolstadt_weather_weekly = unique(weatherstack_kelheim_weekly)
print(ingolstadt_weather_weekly)
mob_joined_with_ingolstadt = ingolstadt_weather_weekly %>%
inner_join(snz_mobility_kelheim_year_week, by = "year_week") %>%
select(-date.x) %>%
rename(date = date.y) %>%
replace_na(list(tmax = 0))
print(mob_joined_with_ingolstadt)
#First plot with colour as precipitation
fills <- c("Ingolstadt" = "blue", "Berlin" = "red")
plt_ing_color = ggplot(mob_joined_with_ingolstadt)+
geom_point(aes(x = date,y = not_at_home_change,colour = prcp_week,fill = "Ingolstadt"))+
geom_point(data = mob_joined_with_weather_berlin,aes(x = date,y = not_at_home_change,colour = prcp_week,fill = "Berlin"))+
scale_color_gradient(low = "white",high = "black")+
scale_fill_manual(values = fills)
ggplotly(plt_ing_color)
plt_ing_color = ggplot(mob_joined_with_ingolstadt)+
geom_point(aes(x = date,y = not_at_home_change))+
geom_line(aes(x = date,y = prcp_week,color = "Ingolstadt"))+
#geom_line(data = berlin_weather_weekly,aes(x = date,y = prcp_week,color = "Berlin"))+
scale_color_manual(values = fills)+
ggtitle("Kelheim mobility with precipitation as line plot on same axis")
ggplotly(plt_ing_color)
# replace coluumn positioning
mob_joined_with_weather_berlin = mob_joined_with_weather_berlin %>% select(year_week,prcp_week,tavg,snow_week,wspd,tmax,date,not_at_home_change)
mob_joined_with_weather_berlin = mob_joined_with_weather_berlin %>% mutate(landkreis = "Berlin")
mob_joined_with_ingolstadt = mob_joined_with_ingolstadt %>% mutate(landkreis = "Ingolstadt")
mob_joined_with_ing_berlin = rbind(mob_joined_with_ingolstadt,mob_joined_with_weather_berlin)
plt_hist_precip_ing = ggplot(mob_joined_with_ing_berlin,aes(x = prcp_week,y = not_at_home_change,fill = landkreis))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 2,position = position_dodge())
ggplotly(plt_hist_precip_ing)
plt_hist_precip_ing = ggplot(mob_joined_with_ing_berlin,aes(x = tavg,y = not_at_home_change,fill = landkreis))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 2,position = position_dodge2())
ggplotly(plt_hist_precip_ing)
plt_hist_precip_ing = ggplot(mob_joined_with_ing_berlin,aes(x = tmax,y = not_at_home_change,fill = landkreis))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 2)
ggplotly(plt_hist_precip_ing)
plt_hist_precip_ing = ggplot(mob_joined_with_ing_berlin,aes(x = snow_week,y = not_at_home_change,fill = landkreis))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 5)
ggplotly(plt_hist_precip_ing)
Warning: Removed 1 rows containing non-finite values (stat_summary_bin).
After first look at data, we can assume that hours out of home
strongly depend on average temperature outside, that sounds logical. Mb
categorization seasons of the data will help to understand this
function
mob_joined_with_ing_berlin = mob_joined_with_ing_berlin %>%
mutate(season = ifelse(month(date) %in% c(12,1,2),"winter",NA)) %>%
mutate(season = ifelse(month(date) %in% c(3,4,5),"spring",season)) %>%
mutate(season = ifelse(month(date) %in% c(6,7,8),"summer",season)) %>%
mutate(season = ifelse(month(date) %in% c(9,10,11),"autumn",season))
#insert also a data about overall in germany
plt_hist_season = ggplot(mob_joined_with_ing_berlin,aes(x = season,y = not_at_home_change,fill = landkreis))+
stat_summary_bin(fun = "mean",
geom = "bar",
binwidth = 5,position = position_dodge())
ggplotly(plt_hist_season)
So it seems that season has an enormous impact at mobility of
citizens. Another important parameter can be description of the weather
based on Kelheim statistics, we will merge it into Ingolstadt weather,
because of the assumption, that Ingolstadt ad Kelheim have the similar
weather properties.
type_of_weather = unique(weatherstack_kelheim$description)
weatherstack_kelheim_year_week = weatherstack_kelheim %>% mutate(year_week = paste0(isoyear(date),"-",isoweek(date)))
week_description_impact = weatherstack_kelheim_year_week %>% group_by(year_week) %>% count(description)
week_description_impact = week_description_impact %>% pivot_wider(names_from = description,values_from = n)
#remove NAs
week_description_impact[is.na(week_description_impact)] = 0
print(week_description_impact)
mob_joined_with_ingolstadt_description = mob_joined_with_ingolstadt %>% inner_join(week_description_impact, by = "year_week")
#normalize it to a percentage
mob_joined_with_ingolstadt_description[type_of_weather] = mob_joined_with_ingolstadt_description[type_of_weather]/168 #168 hours a week
#Assumption not_at_home_change is calculated through individual weather impact normally
#=> each type of weather for the weak get its own weather impact based on not_at_home
#mob_joined_with_ingolstadt_description[type_of_weather] = mob_joined_with_ingolstadt_description[type_of_weather]*mob_joined_with_ingolstadt_description$not_at_home_change
print(mob_joined_with_ingolstadt_description)
mob_joined_with_ingolstadt_description_longer = mob_joined_with_ingolstadt_description%>% pivot_longer(cols = all_of(type_of_weather),names_to = "description")
description_impact_overall = mob_joined_with_ingolstadt_description_longer %>%
group_by(description) %>% summarize(impact = mean(value))
plot_ly(data = description_impact_overall,x = ~description,y = ~impact,type= "bar")
Starting with a model
After first data preparation and analysis, let’s try to make some
predicitions about not_at_home duration based on plots that shown us a
major impact on not_at_home variable, like tavg,
season, description, tavg. Starting with a
linear model and using Ingolstadt data limited by year
2020,2021
mob_joined_with_ingolstadt_description = mob_joined_with_ingolstadt_description %>%
mutate(season = ifelse(month(date) %in% c(12,1,2),"winter",NA)) %>%
mutate(season = ifelse(month(date) %in% c(3,4,5),"spring",season)) %>%
mutate(season = ifelse(month(date) %in% c(6,7,8),"summer",season)) %>%
mutate(season = ifelse(month(date) %in% c(9,10,11),"autumn",season))
train_data = mob_joined_with_ingolstadt_description %>% filter(year(date)<2022)
first_model = lm(not_at_home_change ~ season*prcp_week*tavg,
data = train_data)
test_data = mob_joined_with_ingolstadt_description %>% add_predictions(model = first_model) %>% add_residuals(model = first_model)
ggplot(test_data) +
geom_line(aes(x = date,y = not_at_home_change,color = c("blue" = "actual")))+
geom_line(aes(x = date,y = pred,color = c("red" = "predicted")))

LS0tDQp0aXRsZTogIkJhZCB3ZWF0aGVyIEtlbGhlaW0gRGVtbyINCmF1dGhvcjogIk9sZWtzYW5kciBTb2JvbGlldiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0aGVtZTogY29zbW8NCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCnJ1bnRpbWU6IHNoaW55DQplZGl0b3Jfb3B0aW9uczoNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyLCBpbmNsdWRlPSBGQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkocm1hcmtkb3duKQ0KbGlicmFyeShtb2RlbHIpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIyAqKlJlc2VhcmNoIE1ldGVvc3RhdCoqDQoNCkFmdGVyIHNvbWUgcmVzZWFyY2hlcyBhYm91dCBtZXRlb3N0YXQgZGF0YSBuZWFyZXN0IHN0YXRpb24gaW4gREUgdGhhdCBiZWxvbmdzIHRvIEtlbGhlaW0gcmVnaW9uIGFyZToNCg0KLSAgICJNYWxsZXJzZG9yZi1QZmFmZmVuYmVyZy9OaWVkZXJiYXllcm4iIHdpdGggYW4gaWQ6ICJEMzE0NyINCi0gICAiTmV1bWFya3QgLyBIw7ZoZW5iZXJnIiB3aXRoIGFuZCBpZDogIjY5MTEwIg0KLSAgIFVlYnVuZ3Nkb3JmIC8gRW1ob2YNCg0KdGhlcmUgYXJlIG1hbnkgb2YgdGhlbSBzbyBJIGFtIHN0YXJ0aW5nIHRvIHRoaW5rIGFib3V0IGV4dHJhY3RpbmcgYWxsIGZyb20gdGhlIEJheWVybiBvciBleHRyYWN0IHRoZSBuZWFyZXN0IGZyb20gbG9uZ3RpdHVkZS9sYXRpdHVkZSBwb2ludCB3aXRoIHRoZSBLZWxoZWltIHNoYXBlZmlsZSh1c2luZyBqc29uIGFuZCBFdWNsaWQgZGlzdGFuY2VzKQ0KDQpbS2VsaGVpbSBoYXMgbm8gd2VhdGhlciBzdGF0aW9uLCBidXQgaXQgY291bGQgYmUgcmVjb25zdHJ1Y3RlZCB3aXRoIDIgb3RoZXJdKGh0dHBzOi8vd2VhdGhlcnNwYXJrLmNvbS95LzcwMzcwL0F2ZXJhZ2UtV2VhdGhlci1pbi1LZWxoZWltLUdlcm1hbnktWWVhci1Sb3VuZCkNCg0KSG9oZW5mZWxzIHdpdGggaWQ6ICIxMDc3NSIgYW5kIEluZ29sc3RhZHQgd2l0aCBpZDoiMTA4NjAiICoqa2VsaGVpbV9kYXRhID0ge3dlaWdodDF9eHtob2hlbmZlbHN9ICsge3dlaWdodDJ9eHtpbmdsc3RhZHR9KioNCg0KQWxzbyB0aGlzIHNpdGUgc2hvd3MsIHRoYXQgdGhlcmUgYXJlIG1hbnkgb2YgdGhlIEtlbGhlaW0gc3RhdGlvbnMgaW4gdGhpcyBhcmVhLCBidXQgbWV0ZW9zdGF0IGRvZXNuJ3QgY29udGFpbiB0aGVtIDxodHRwczovL3d3dy53dW5kZXJncm91bmQuY29tL2Rhc2hib2FyZC9wd3MvSUtFTEhFNT4NCg0KIyMgKipSZXNlYXJjaCBXZWF0aGVyc3RhY2sqKg0KDQpgYGB7ciBmaXJzdCBsb29rIGF0IHdlYXRoZXJzdGFjayBkYXRhIHNwZWNpZmljIHRvIEtlbGhlaW19DQp3ZWF0aGVyc3RhY2tfa2VsaGVpbSA9IHJlYWRfZGVsaW0oImRhdGEvS2VsaGVpbV93ZWF0aGVyX3NpbmNlX2p1bHlfMjAwOC5jc3YiLGRlbGltID0gIiwiKQ0KcHJpbnQod2VhdGhlcnN0YWNrX2tlbGhlaW0pDQpgYGANCg0KV2hhdCB0byB0YWtlIGFzIGEgcmVmZmVyIHBvaW50IGlzbid0IGNsZWFyIGJlY2F1c2Ugb2YgdGhlIGRhdGUoYmVmb3JlL2FmdGVyIGNvdmlkKSBhbmQgd2VhdGhlciB0eXBlIChzdW5ueSxjbGVhcix0ZW1wZXJhdHVyZSkgQWxzbyB0aGVyZSBpcyBubyB0ZW1wZXJhdHVyZSBpbiBpdCA6Lw0KDQojIyAqKkltcG9ydCBtb2JpbGl0eSBmcm9tIEdvb2dsZSoqDQoNCmBgYHtyIGluY2x1ZGluZyBnb29nbGUgZ2VybWFueSBtb2JpbGl0eSBkYXRhLG1lc3NhZ2U9RkFMU0V9DQojZ2xvYmFsX21vYmlsaXR5ID0gcmVhZF9kZWxpbSgiaHR0cHM6Ly93d3cuZ3N0YXRpYy5jb20vY292aWQxOS9tb2JpbGl0eS9HbG9iYWxfTW9iaWxpdHlfUmVwb3J0LmNzdiIsIiwiKQ0KI2RlX21vYmlsaXR5ID0gZ2xvYmFsX21vYmlsaXR5ICU+JSBmaWx0ZXIoY291bnRyeV9yZWdpb25fY29kZSA9PSAiREUiKQ0KYGBgDQoNCmBgYHtyIHdoYXQgcmVnaW9ucyBhcmUgZGF0YSBwcm92aWRlZH0NCiNwcmludCh1bmlxdWUoZGVfbW9iaWxpdHkkc3ViX3JlZ2lvbl8xKSkNCg0KYGBgDQoNCkFzIHdlIGNhbiBzZWUgdGhlIG1vc3QgcHJlY2lzZSByZWdpb24gdG8gZmlsdGVyIGRhdGEgZnJvbSBpcyBCYXZhcmlhIDovDQoNClJlbGV2YW50IGRhdGEgZm9yIHRoZSAsIG1vYmlsaXR5DQoNCmBgYHtyIG1vYmlsaXR5IGRhdGEgYmF2YXJpYX0NCiNiYXZhcmlhX21vYmlsaXR5ID0gZGVfbW9iaWxpdHkgJT4lIGZpbHRlcihzdWJfcmVnaW9uXzEgPT0gIkJhdmFyaWEiKQ0KI2JhdmFyaWFfbW9iaWxpdHkgPSBiYXZhcmlhX21vYmlsaXR5ICU+JSAjc2VsZWN0KGNvdW50cnlfcmVnaW9uLHN1Yl9yZWdpb25fMSxkYXRlLHJlc2lkZW50aWFsX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUpICU+JQ0KIyAgbXV0YXRlKHJlc2lkZW50aWFsX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUgPSAtcmVzaWRlbnRpYWxfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSwNCiMgICAgICAgICBzb3VyY2UgPSAiR29vZ2xlIiklPiUNCiMgIHJlbmFtZShCdW5kZXNsYW5kSUQgPSBzdWJfcmVnaW9uXzEsbm90X2F0X2hvbWVfY2hhbmdlID0gcmVzaWRlbnRpYWxfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSkNCiNiYXZhcmlhX21vYmlsaXR5ID0gYmF2YXJpYV9tb2JpbGl0eSAlPiUgc2VsZWN0KGRhdGUsQnVuZGVzbGFuZElELG5vdF9hdF9ob21lX2NoYW5nZSxzb3VyY2UpDQojTmVlZCB0byBmaWx0ZXIgb3V0IHdlZWtlbmRzDQoNCiNwbHQgPSBnZ3Bsb3QoYmF2YXJpYV9tb2JpbGl0eSkrDQojICBnZW9tX3BvaW50KGFlcyh4ID0gZGF0ZSx5ID0gbm90X2F0X2hvbWVfY2hhbmdlKSkNCiNnZ3Bsb3RseShwbHQpDQpgYGANCg0KIyMgKipJbXBvcnQgbW9iaWxpdHkgZnJvbSBTZW5vem9uKioNCg0KYGBge3IgaW1wb3J0IGZyb20gc2Vub3pvbn0NCnNuel9tb2JpbGl0eSA9IHJlYWRfZGVsaW0oImRhdGEvTEtfbW9iaWxpdHlEYXRhX3dlZWtkYXlzLmNzdiIsIjsiKQ0KDQojS2VsaGVpbQ0Kc256X21vYmlsaXR5X2tlbGhlaW0gPSBzbnpfbW9iaWxpdHkgJT4lIGZpbHRlcihMYW5ka3JlaXMgPT0gIkxhbmRrcmVpcyBLZWxoZWltIikgJT4lIG11dGF0ZShzb3VyY2UgPSAic2Vub3pvbiIpICU+JSBzZWxlY3QoLW91dE9mSG9tZUR1cmF0aW9uKSAlPiUgcmVuYW1lKG5vdF9hdF9ob21lX2NoYW5nZSA9IHBlcmNlbnRhZ2VDaGFuZ2VDb21wYXJlZFRvQmVmb3JlQ29yb25hKQ0Kc256X21vYmlsaXR5X2tlbGhlaW0kZGF0ZSA9IGFzLkRhdGUoc3RycHRpbWUoc256X21vYmlsaXR5X2tlbGhlaW0kZGF0ZSwiJVklbSVkIikpDQoNCiNCZXJsaW4NCnNuel9tb2JpbGl0eV9iZXJsaW4gPSBzbnpfbW9iaWxpdHkgJT4lIGZpbHRlcihMYW5ka3JlaXMgPT0gIkJlcmxpbiIpICU+JSBtdXRhdGUoc291cmNlID0gInNlbm96b24iKSAlPiUgc2VsZWN0KC1vdXRPZkhvbWVEdXJhdGlvbikgJT4lIHJlbmFtZShub3RfYXRfaG9tZV9jaGFuZ2UgPSBwZXJjZW50YWdlQ2hhbmdlQ29tcGFyZWRUb0JlZm9yZUNvcm9uYSkNCnNuel9tb2JpbGl0eV9iZXJsaW4kZGF0ZSA9IGFzLkRhdGUoc3RycHRpbWUoc256X21vYmlsaXR5X2JlcmxpbiRkYXRlLCIlWSVtJWQiKSkNCg0KY29sb3JzIDwtIGMoIkJlcmxpbiIgPSAiYmx1ZSIsICJLZWxoZWltIiA9ICJyZWQiKQ0KDQpwbHQgPSBnZ3Bsb3QoKSsNCiAgZ2VvbV9wb2ludChkYXRhID0gc256X21vYmlsaXR5X2tlbGhlaW0sYWVzKHggPSBkYXRlLHkgPSBub3RfYXRfaG9tZV9jaGFuZ2UsY29sb3IgPSAiQmVybGluIikpKw0KICBnZW9tX3BvaW50KGRhdGEgPSBzbnpfbW9iaWxpdHlfYmVybGluLGFlcyh4ID0gZGF0ZSx5ID0gbm90X2F0X2hvbWVfY2hhbmdlLGNvbG9yID0gIktlbGhlaW0iKSkrDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sb3JzKQ0KZ2dwbG90bHkocGx0KQ0KYGBgDQoNCiMjICoqQWdncmVnYXRlIDIgc291cmNlcyoqDQoNCldlIHRha2UgYmVybGluIHdlYXRoZXIgZnJvbSBzdGF0aW9uIGluIFNjaG9lbmVmZWxkIHdpdGggaWQgPSAxMDM4NA0KYGBge3IgYWRkaW5nIGJlcmxpbiB3ZWF0aGVyLCBlY2hvPUZBTFNFfQ0KYmVybGluX3dlYXRoZXJfZGFpbHkgPSByZWFkX2RlbGltKCJodHRwczovL2J1bGsubWV0ZW9zdGF0Lm5ldC92Mi9kYWlseS8xMDM4NS5jc3YuZ3oiLCIsIixjb2xfbmFtZXMgPSBGQUxTRSkNCmNvbG5hbWVzKGJlcmxpbl93ZWF0aGVyX2RhaWx5KSA9IGMoImRhdGUiLCAidGF2ZyIsICJ0bWluIiwgInRtYXgiLCAicHJjcCIsICJzbm93IiwgIndkaXIiLCAid3NwZCIsICJ3cGd0IiwgInByZXMiLCAidHN1biIpDQpgYGANCg0KDQpgYGB7ciBkZWZpbmUgd2VhdGhlciBkYXRhIGFzIHdlZWsgZGF0YX0NCiMgdGhpbmsgYWJvdXQgZHVyYXRpb24gb2YgZGVzY3JpcHRpb24gY29sdW1uDQojIEtlbGhlaW0NCndlYXRoZXJzdGFja19rZWxoZWltX2RhaWx5ID0gd2VhdGhlcnN0YWNrX2tlbGhlaW0gJT4lDQogIGdyb3VwX2J5KGRhdGUpICU+JQ0KICBzdW1tYXJpemUoZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbixwcmVjaXBfZGF5ID0gc3VtKHByZWNpcCksdmlzaWJpbGl0eV9tZWFuID0gbWVhbih2aXNpYmlsaXR5KSx0b3RhbHNub3dfZGFpbHkgPSBtZWFuKHRvdGFsc25vd19kYWlseSkpDQogIA0Kd2VhdGhlcnN0YWNrX2tlbGhlaW1fd2Vla2x5ID0gd2VhdGhlcnN0YWNrX2tlbGhlaW1fZGFpbHkgJT4lIA0KICBtdXRhdGUoeWVhcl93ZWVrID0gcGFzdGUwKGlzb3llYXIoZGF0ZSksIi0iLGlzb3dlZWsoZGF0ZSkpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcl93ZWVrKSAlPiUNCiAgc3VtbWFyaXplKGRlc2NyaXB0aW9uID0gZGVzY3JpcHRpb24sZGF0ZSA9IGZpcnN0KGRhdGUpLCBwcmVjaXBfd2VlayA9IHN1bShwcmVjaXBfZGF5KSx2aXNpYmlsaXR5X21lYW4gPSBtZWFuKHZpc2liaWxpdHlfbWVhbiksdG90YWxzbm93X3dlZWtseSA9c3VtKCB0b3RhbHNub3dfZGFpbHkpKQ0Kd2VhdGhlcnN0YWNrX2tlbGhlaW1fd2Vla2x5ID0gdW5pcXVlKHdlYXRoZXJzdGFja19rZWxoZWltX3dlZWtseSkNCnByaW50KHdlYXRoZXJzdGFja19rZWxoZWltX3dlZWtseSkNCg0KI0Jlcmxpbg0KICANCmJlcmxpbl93ZWF0aGVyX3dlZWtseSA9IGJlcmxpbl93ZWF0aGVyX2RhaWx5ICU+JSBmaWx0ZXIoeWVhcihkYXRlKSA+PTIwMjApICU+JQ0KICBtdXRhdGUoeWVhcl93ZWVrID0gcGFzdGUwKGlzb3llYXIoZGF0ZSksIi0iLGlzb3dlZWsoZGF0ZSkpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcl93ZWVrKSAlPiUNCiAgc3VtbWFyaXplKGRhdGUgPSBmaXJzdChkYXRlKSwgcHJjcF93ZWVrID0gc3VtKHByY3ApLCB0YXZnPSBtZWFuKHRhdmcpLHNub3dfd2VlayA9c3VtKCBzbm93KSx3c3BkID0gbWVhbih3c3BkKSx0bWF4ID0gbWF4KHRtYXgpKSAlPiUNCiAgYXJyYW5nZSh5ZWFyX3dlZWspDQpwcmludChiZXJsaW5fd2VhdGhlcl93ZWVrbHkpDQogIA0KYGBgDQoNCmBgYHtyIGdvb2dsZStzZW5vem9uK3dlYXRoZXJ9DQojbW9iX2pvaW5lZCA9IHJiaW5kKHNuel9tb2JpbGl0eV9rZWxoZWltLGJhdmFyaWFfbW9iaWxpdHkpDQojS2VsaGVpbQ0Kc256X21vYmlsaXR5X2tlbGhlaW1feWVhcl93ZWVrID0gc256X21vYmlsaXR5X2tlbGhlaW0gJT4lIA0KICBtdXRhdGUoeWVhcl93ZWVrID0gcGFzdGUwKGlzb3llYXIoZGF0ZSksIi0iLGlzb3dlZWsoZGF0ZSkpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcl93ZWVrKSAlPiUNCiAgc3VtbWFyaXplKGRhdGUgPSBmaXJzdChkYXRlKSxub3RfYXRfaG9tZV9jaGFuZ2UgPSBtZWFuKG5vdF9hdF9ob21lX2NoYW5nZSkpDQptb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9rZWxoZWltID0gc256X21vYmlsaXR5X2tlbGhlaW1feWVhcl93ZWVrICU+JSBpbm5lcl9qb2luKHdlYXRoZXJzdGFja19rZWxoZWltX3dlZWtseSwgYnkgPSAieWVhcl93ZWVrIikgJT4lIHNlbGVjdCgtZGF0ZS55KSAlPiUgcmVuYW1lKGRhdGUgPSBkYXRlLngpDQpwcmludChtb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9rZWxoZWltKQ0KDQojQmVybGluDQpzbnpfbW9iaWxpdHlfYmVybGluX3llYXJfd2VlayA9IHNuel9tb2JpbGl0eV9iZXJsaW4gJT4lIA0KICBtdXRhdGUoeWVhcl93ZWVrID0gcGFzdGUwKGlzb3llYXIoZGF0ZSksIi0iLGlzb3dlZWsoZGF0ZSkpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcl93ZWVrKSAlPiUNCiAgc3VtbWFyaXplKGRhdGUgPSBmaXJzdChkYXRlKSxub3RfYXRfaG9tZV9jaGFuZ2UgPSBtZWFuKG5vdF9hdF9ob21lX2NoYW5nZSkpDQptb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9iZXJsaW4gPSBzbnpfbW9iaWxpdHlfYmVybGluX3llYXJfd2VlayAlPiUgaW5uZXJfam9pbihiZXJsaW5fd2VhdGhlcl93ZWVrbHksIGJ5ID0gInllYXJfd2VlayIpICU+JSBzZWxlY3QoLWRhdGUueSkgJT4lIHJlbmFtZShkYXRlID0gZGF0ZS54KQ0KcHJpbnQobW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfYmVybGluKQ0KYGBgDQoNCmBgYHtyIGZpcnN0IHBsb3R9DQojRmlyc3QgcGxvdCB3aXRoIGNvbG91ciBhcyBwcmVjaXBpdGF0aW9uDQpzaGFwZXMgPC0gYygiQmVybGluIiA9IDUsICJLZWxoZWltIiA9IDMpDQpwbHRfY29sb3IgPSBnZ3Bsb3QoKSsNCiAgZ2VvbV9wb2ludChkYXRhID0gbW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfa2VsaGVpbSxhZXMoeCA9IGRhdGUseSA9IG5vdF9hdF9ob21lX2NoYW5nZSxjb2xvdXIgPSBwcmVjaXBfd2VlayxzaGFwZSA9ICJLZWxoZWltIikpKw0KICAjZ2VvbV9wb2ludChkYXRhID0gbW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfYmVybGluLGFlcyh4ID0gZGF0ZSx5ID0gbm90X2F0X2hvbWVfY2hhbmdlLGNvbG91ciA9IHByY3Bfd2VlayxzaGFwZSA9ICJCZXJsaW4iKSkrDQogIHNjYWxlX2NvbG9yX2dyYWRpZW50MigpKw0KICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc2hhcGVzKQ0KICANCg0KZ2dwbG90bHkocGx0X2NvbG9yKQ0KYGBgDQoNCmBgYHtyIHNlY29uZCBwbG90fQ0KI1NlY29uZCBwbG90IGFzIGFub3RoZXIgbGluZSBhcyBwcmVjaXBpdGF0aW9uDQpwbHRfbGluZSA9IGdncGxvdChtb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9rZWxoZWltKSsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRhdGUseSA9IG5vdF9hdF9ob21lX2NoYW5nZSkpKw0KICBnZW9tX2xpbmUoYWVzKHggPSBkYXRlLHkgPSBwcmVjaXBfd2VlayowLjUsY29sb3IgPSAicmVkIikpDQogIA0KDQpnZ3Bsb3RseShwbHRfbGluZSkNCmBgYA0KDQpgYGB7ciBwcmVjaXBpdGF0aW9uIGhpc3RvZ3JhbX0NCnBsdF9oaXN0X3ByZWNpcCA9IGdncGxvdChtb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9rZWxoZWltLGFlcyh4ID0gcHJlY2lwX3dlZWsseSA9IG5vdF9hdF9ob21lX2NoYW5nZSkpKw0KICBzdGF0X3N1bW1hcnlfYmluKGZ1biA9ICJtZWFuIiwNCiAgICAgICAgICAgICAgICAgICBnZW9tID0gImJhciIsDQogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSAyLGZpbGwgPSAiYmx1ZSIpDQoNCmdncGxvdGx5KHBsdF9oaXN0X3ByZWNpcCkNCmBgYA0KDQpgYGB7ciB2aXNpYmlsaXR5IGhpc3RvZ3JhbX0NCnBsdF9oaXN0X3Zpc2liaWxpdHkgPSBnZ3Bsb3QobW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfa2VsaGVpbSxhZXMoeCA9IHZpc2liaWxpdHlfbWVhbix5ID0gbm90X2F0X2hvbWVfY2hhbmdlKSkrDQogIHN0YXRfc3VtbWFyeV9iaW4oZnVuID0gIm1lYW4iLA0KICAgICAgICAgICAgICAgICAgIGdlb20gPSAiYmFyIiwNCiAgICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDAuNSxmaWxsID0gImJsdWUiKQ0KDQpnZ3Bsb3RseShwbHRfaGlzdF92aXNpYmlsaXR5KQ0KYGBgDQoNCmBgYHtyIHRvdGFsc25vdyBoaXN0b2dyYW19DQpwbHRfaGlzdF90b3RhbHNub3cgPSBnZ3Bsb3QobW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfa2VsaGVpbSxhZXMoeCA9IHRvdGFsc25vd193ZWVrbHkseSA9IG5vdF9hdF9ob21lX2NoYW5nZSkpKw0KICBzdGF0X3N1bW1hcnlfYmluKGZ1biA9ICJtZWFuIiwNCiAgICAgICAgICAgICAgICAgICBnZW9tID0gImJhciIsDQogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSA3LGZpbGwgPSAiYmx1ZSIpDQoNCmdncGxvdGx5KHBsdF9oaXN0X3RvdGFsc25vdykNCmBgYA0KDQpgYGB7ciBsb29raW5nIGF0IGRlc2NyaXB0aW9uIGNvbHVtbn0NCiN0aGlzIGlzIGEgYmFkIHBsb3QgYmVjYXVzZSBpdCB0YWtlcyBkZXNjcmlwdGlvbiBvZiAxIGRheSBvZiB0aGUgd2Vlaw0KcGx0X2hpc3RfZGVzY3IgPSBnZ3Bsb3QobW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfa2VsaGVpbSxhZXMoeCA9IGRlc2NyaXB0aW9uLHkgPSBub3RfYXRfaG9tZV9jaGFuZ2UpKSsNCiAgc3RhdF9zdW1tYXJ5X2JpbihmdW4gPSAibWVhbiIsDQogICAgICAgICAgICAgICAgICAgZ2VvbSA9ICJiYXIiLA0KICAgICAgICAgICAgICAgICAgIGJpbndpZHRoID0gNSxmaWxsID0gImJsdWUiKSsNCiAgY29vcmRfZmxpcCgpDQoNCmdncGxvdGx5KHBsdF9oaXN0X2Rlc2NyKQ0KYGBgDQoNCiMjIExldCdzIHRyeSBpdCBvdXQgd2l0aCBtZXRlb3N0YXQgZGF0YSwgdGhhdCBjb250YWlucyBzY29wZSBvZiB0aGUgMjAyMiB3aXRob3V0IHJlc3RpY3Rpb25zDQoNCkluZ29sc3RhZHQgZGF0YSBmcm9tIGlkID0gMTA4NjAgc3RhdGlvbg0KDQpgYGB7ciBJbmdvbHN0YWR0IGRhdGF9DQppbmdvbHN0YWR0X3dlYXRoZXIgPSByZWFkX2RlbGltKCJodHRwczovL2J1bGsubWV0ZW9zdGF0Lm5ldC92Mi9kYWlseS8xMDg2MC5jc3YuZ3oiLCIsIixjb2xfbmFtZXMgPSBGQUxTRSkNCg0KY29sbmFtZXMoaW5nb2xzdGFkdF93ZWF0aGVyKSA9IGMoImRhdGUiLCAidGF2ZyIsICJ0bWluIiwgInRtYXgiLCAicHJjcCIsICJzbm93IiwgIndkaXIiLCAid3NwZCIsICJ3cGd0IiwgInByZXMiLCAidHN1biIpDQoNCg0KIyBXZSBkb24ndCBuZWVkIGRhdGEgb2Ygd2VhdGhlciBiZWZvcmUgMjAyMCwgYmVjYXVzZSBvZiBzbnpfbW9iaWxpdHkgZGF0ZSwgYWxzbyBkYXRhIGlzbid0IHByZWNpc2UNCg0KaW5nb2xzdGFkdF93ZWF0aGVyID0gaW5nb2xzdGFkdF93ZWF0aGVyICU+JSBmaWx0ZXIoeWVhcihkYXRlKT49MjAyMCklPiUgcmVwbGFjZV9uYShsaXN0KHNub3cgPSAwKSkNCg0KcHJpbnQoaW5nb2xzdGFkdF93ZWF0aGVyKQ0KYGBgDQoNCkhvaGVuZmVscyBkYXRhIGZyb20gaWQgPSAxMDc3NSBzdGF0aW9uDQoNCmBgYHtyIEhvaGVuZmVscyBkYXRhfQ0KaG9oZW5mZWxzX3dlYXRoZXIgPSByZWFkX2RlbGltKCJodHRwczovL2J1bGsubWV0ZW9zdGF0Lm5ldC92Mi9kYWlseS8xMDc3NS5jc3YuZ3oiLCIsIixjb2xfbmFtZXMgPSBGQUxTRSkNCg0KY29sbmFtZXMoaG9oZW5mZWxzX3dlYXRoZXIpID0gYygiZGF0ZSIsICJ0YXZnIiwgInRtaW4iLCAidG1heCIsICJwcmNwIiwgInNub3ciLCAid2RpciIsICJ3c3BkIiwgIndwZ3QiLCAicHJlcyIsICJ0c3VuIikNCg0KDQojIFdlIGRvbid0IG5lZWQgZGF0YSBvZiB3ZWF0aGVyIGJlZm9yZSAyMDIwLCBiZWNhdXNlIG9mIHNuel9tb2JpbGl0eSBkYXRlLCBhbHNvIGRhdGEgaXNuJ3QgcHJlY2lzZQ0KDQpob2hlbmZlbHNfd2VhdGhlciA9IGhvaGVuZmVsc193ZWF0aGVyICU+JSBmaWx0ZXIoeWVhcihkYXRlKT49MjAyMCkgJT4lIHJlcGxhY2VfbmEobGlzdChzbm93ID0gMCkpDQoNCnByaW50KGhvaGVuZmVsc193ZWF0aGVyKQ0KYGBgDQoNCkFzIHdlIGNhbiBzZWUgaW4gSG9oZW5mZWxzIGRhdGEgaXNuJ3QgdGhhdCBhY2N1cmF0ZSBhbmQgcHJlY2lwaXRhdGlvbiBpcyBkYXRhIGlzIG1pc3NpbmcgZnIgeWVhciAyMDIwLCBzbyBmb3IgdGhlIGZ1cnRoZXIgYW5hbHlzaXMgd2UgdGFrZSBvbmx5IEluZ29sc3RhZHQgZGF0YS4NCg0KYGBge3IgSW5nb2xzdGFkdCB3ZWVrbHkgZGF0YX0NCmluZ29sc3RhZHRfd2VhdGhlcl93ZWVrbHkgPSBpbmdvbHN0YWR0X3dlYXRoZXIgJT4lIA0KICBtdXRhdGUoeWVhcl93ZWVrID0gcGFzdGUwKGlzb3llYXIoZGF0ZSksIi0iLGlzb3dlZWsoZGF0ZSkpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcl93ZWVrKSAlPiUNCiAgc3VtbWFyaXplKGRhdGUgPSBmaXJzdChkYXRlKSwgcHJjcF93ZWVrID0gc3VtKHByY3ApLCB0YXZnPSBtZWFuKHRhdmcpLHNub3dfd2VlayA9c3VtKCBzbm93KSx3c3BkID0gbWVhbih3c3BkKSx0bWF4ID0gbWF4KHRtYXgpKSAlPiUNCiAgYXJyYW5nZSh5ZWFyX3dlZWspDQojaW5nb2xzdGFkdF93ZWF0aGVyX3dlZWtseSA9IHVuaXF1ZSh3ZWF0aGVyc3RhY2tfa2VsaGVpbV93ZWVrbHkpDQpwcmludChpbmdvbHN0YWR0X3dlYXRoZXJfd2Vla2x5KQ0KYGBgDQoNCmBgYHtyIGFnZ3JlZ2F0ZSBzbnogYW5kIGluZ29sc3RhZHR9DQptb2Jfam9pbmVkX3dpdGhfaW5nb2xzdGFkdCA9IGluZ29sc3RhZHRfd2VhdGhlcl93ZWVrbHkgJT4lIA0KICBpbm5lcl9qb2luKHNuel9tb2JpbGl0eV9rZWxoZWltX3llYXJfd2VlaywgYnkgPSAieWVhcl93ZWVrIikgJT4lIA0KICBzZWxlY3QoLWRhdGUueCkgJT4lDQogIHJlbmFtZShkYXRlID0gZGF0ZS55KSAlPiUNCiAgcmVwbGFjZV9uYShsaXN0KHRtYXggPSAwKSkNCg0KcHJpbnQobW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHQpDQpgYGANCg0KYGBge3IgY29sb3JlZCBwcmVjaXBpdGF0aW9uIHBsb3QgSW5nb2xzdGFkdH0NCiNGaXJzdCBwbG90IHdpdGggY29sb3VyIGFzIHByZWNpcGl0YXRpb24NCmZpbGxzIDwtIGMoIkluZ29sc3RhZHQiID0gImJsdWUiLCAiQmVybGluIiA9ICJyZWQiKQ0KcGx0X2luZ19jb2xvciA9IGdncGxvdChtb2Jfam9pbmVkX3dpdGhfaW5nb2xzdGFkdCkrDQogIGdlb21fcG9pbnQoYWVzKHggPSBkYXRlLHkgPSBub3RfYXRfaG9tZV9jaGFuZ2UsY29sb3VyID0gcHJjcF93ZWVrLGZpbGwgPSAiSW5nb2xzdGFkdCIpKSsNCiAgZ2VvbV9wb2ludChkYXRhID0gbW9iX2pvaW5lZF93aXRoX3dlYXRoZXJfYmVybGluLGFlcyh4ID0gZGF0ZSx5ID0gbm90X2F0X2hvbWVfY2hhbmdlLGNvbG91ciA9IHByY3Bfd2VlayxmaWxsID0gIkJlcmxpbiIpKSsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIndoaXRlIixoaWdoID0gImJsYWNrIikrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGZpbGxzKQ0KDQpnZ3Bsb3RseShwbHRfaW5nX2NvbG9yKQ0KYGBgDQoNCg0KYGBge3IgcHJlY2lwaXRhdGlvbiBhcyBsaW5lIHBsb3R9DQpwbHRfaW5nX2NvbG9yID0gZ2dwbG90KG1vYl9qb2luZWRfd2l0aF9pbmdvbHN0YWR0KSsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRhdGUseSA9IG5vdF9hdF9ob21lX2NoYW5nZSkpKw0KICBnZW9tX2xpbmUoYWVzKHggPSBkYXRlLHkgPSBwcmNwX3dlZWssY29sb3IgPSAiSW5nb2xzdGFkdCIpKSsNCiAgI2dlb21fbGluZShkYXRhID0gYmVybGluX3dlYXRoZXJfd2Vla2x5LGFlcyh4ID0gZGF0ZSx5ID0gcHJjcF93ZWVrLGNvbG9yID0gIkJlcmxpbiIpKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGZpbGxzKSsNCiAgZ2d0aXRsZSgiS2VsaGVpbSBtb2JpbGl0eSB3aXRoIHByZWNpcGl0YXRpb24gYXMgbGluZSBwbG90IG9uIHNhbWUgYXhpcyIpDQoNCmdncGxvdGx5KHBsdF9pbmdfY29sb3IpDQpgYGANCg0KYGBge3Igam9pbiBpbmdvbHN0YWR0IGFuZCBiZXJsaW4gaW4gMSB0YWJsZX0NCiMgcmVwbGFjZSBjb2x1dW1uIHBvc2l0aW9uaW5nDQoNCm1vYl9qb2luZWRfd2l0aF93ZWF0aGVyX2JlcmxpbiA9IG1vYl9qb2luZWRfd2l0aF93ZWF0aGVyX2JlcmxpbiAlPiUgc2VsZWN0KHllYXJfd2VlayxwcmNwX3dlZWssdGF2Zyxzbm93X3dlZWssd3NwZCx0bWF4LGRhdGUsbm90X2F0X2hvbWVfY2hhbmdlKQ0KDQptb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9iZXJsaW4gPSBtb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9iZXJsaW4gJT4lIG11dGF0ZShsYW5ka3JlaXMgPSAiQmVybGluIikNCg0KbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHQgPSBtb2Jfam9pbmVkX3dpdGhfaW5nb2xzdGFkdCAlPiUgbXV0YXRlKGxhbmRrcmVpcyA9ICJJbmdvbHN0YWR0IikNCg0KbW9iX2pvaW5lZF93aXRoX2luZ19iZXJsaW4gPSByYmluZChtb2Jfam9pbmVkX3dpdGhfaW5nb2xzdGFkdCxtb2Jfam9pbmVkX3dpdGhfd2VhdGhlcl9iZXJsaW4pDQpgYGANCg0KYGBge3IgaGlzdG9ncmFtIHdpdGggcHJlY2lwfQ0KcGx0X2hpc3RfcHJlY2lwX2luZyA9IGdncGxvdChtb2Jfam9pbmVkX3dpdGhfaW5nX2JlcmxpbixhZXMoeCA9IHByY3Bfd2Vlayx5ID0gbm90X2F0X2hvbWVfY2hhbmdlLGZpbGwgPSBsYW5ka3JlaXMpKSsNCiAgc3RhdF9zdW1tYXJ5X2JpbihmdW4gPSAibWVhbiIsDQogICAgICAgICAgICAgICAgICAgZ2VvbSA9ICJiYXIiLA0KICAgICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMixwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSgpKQ0KDQpnZ3Bsb3RseShwbHRfaGlzdF9wcmVjaXBfaW5nKQ0KDQpgYGANCg0KYGBge3IgaGlzdG9ncmFtIHdpdGggYXZlcmFnZSB0ZW1wZXJhdHVyZX0NCnBsdF9oaXN0X3ByZWNpcF9pbmcgPSBnZ3Bsb3QobW9iX2pvaW5lZF93aXRoX2luZ19iZXJsaW4sYWVzKHggPSB0YXZnLHkgPSBub3RfYXRfaG9tZV9jaGFuZ2UsZmlsbCA9IGxhbmRrcmVpcykpKw0KICBzdGF0X3N1bW1hcnlfYmluKGZ1biA9ICJtZWFuIiwNCiAgICAgICAgICAgICAgICAgICBnZW9tID0gImJhciIsDQogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSAyLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UyKCkpDQoNCmdncGxvdGx5KHBsdF9oaXN0X3ByZWNpcF9pbmcpDQoNCmBgYA0KDQpgYGB7ciBoaXN0b2dyYW0gd2l0aCBtYXhpbWFsIHRlbXBlcmF0dXJlfQ0KcGx0X2hpc3RfcHJlY2lwX2luZyA9IGdncGxvdChtb2Jfam9pbmVkX3dpdGhfaW5nX2JlcmxpbixhZXMoeCA9IHRtYXgseSA9IG5vdF9hdF9ob21lX2NoYW5nZSxmaWxsID0gbGFuZGtyZWlzKSkrDQogIHN0YXRfc3VtbWFyeV9iaW4oZnVuID0gIm1lYW4iLA0KICAgICAgICAgICAgICAgICAgIGdlb20gPSAiYmFyIiwNCiAgICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDIpDQoNCmdncGxvdGx5KHBsdF9oaXN0X3ByZWNpcF9pbmcpDQoNCmBgYA0KDQpgYGB7ciBoaXN0b2dyYW0gd2l0aCBzbm93IGF0IHRoZSB3ZWVrfQ0KcGx0X2hpc3RfcHJlY2lwX2luZyA9IGdncGxvdChtb2Jfam9pbmVkX3dpdGhfaW5nX2JlcmxpbixhZXMoeCA9IHNub3dfd2Vlayx5ID0gbm90X2F0X2hvbWVfY2hhbmdlLGZpbGwgPSBsYW5ka3JlaXMpKSsNCiAgc3RhdF9zdW1tYXJ5X2JpbihmdW4gPSAibWVhbiIsDQogICAgICAgICAgICAgICAgICAgZ2VvbSA9ICJiYXIiLA0KICAgICAgICAgICAgICAgICAgIGJpbndpZHRoID0gNSkNCg0KZ2dwbG90bHkocGx0X2hpc3RfcHJlY2lwX2luZykNCg0KYGBgDQoNCkFmdGVyIGZpcnN0IGxvb2sgYXQgZGF0YSwgd2UgY2FuIGFzc3VtZSB0aGF0IGhvdXJzIG91dCBvZiBob21lIHN0cm9uZ2x5IGRlcGVuZCBvbiBhdmVyYWdlIHRlbXBlcmF0dXJlIG91dHNpZGUsIHRoYXQgc291bmRzIGxvZ2ljYWwuIE1iIGNhdGVnb3JpemF0aW9uIHNlYXNvbnMgb2YgdGhlIGRhdGEgd2lsbCBoZWxwIHRvIHVuZGVyc3RhbmQgdGhpcyBmdW5jdGlvbg0KDQpgYGB7ciBhZGRpbmcgbmV3IHNlYXNvbiBjb2x1bW59DQptb2Jfam9pbmVkX3dpdGhfaW5nX2JlcmxpbiA9IG1vYl9qb2luZWRfd2l0aF9pbmdfYmVybGluICU+JSANCiAgbXV0YXRlKHNlYXNvbiA9IGlmZWxzZShtb250aChkYXRlKSAlaW4lIGMoMTIsMSwyKSwid2ludGVyIixOQSkpICU+JQ0KICBtdXRhdGUoc2Vhc29uID0gaWZlbHNlKG1vbnRoKGRhdGUpICVpbiUgYygzLDQsNSksInNwcmluZyIsc2Vhc29uKSkgJT4lDQogIG11dGF0ZShzZWFzb24gPSBpZmVsc2UobW9udGgoZGF0ZSkgJWluJSBjKDYsNyw4KSwic3VtbWVyIixzZWFzb24pKSAlPiUNCiAgbXV0YXRlKHNlYXNvbiA9IGlmZWxzZShtb250aChkYXRlKSAlaW4lIGMoOSwxMCwxMSksImF1dHVtbiIsc2Vhc29uKSkNCmBgYA0KDQoNCmBgYHtyIHNlYXNvbiB+IG5vdF9hdF9ob21lOiAgcGxvdHN9DQojaW5zZXJ0IGFsc28gYSBkYXRhIGFib3V0IG92ZXJhbGwgaW4gZ2VybWFueQ0KcGx0X2hpc3Rfc2Vhc29uID0gZ2dwbG90KG1vYl9qb2luZWRfd2l0aF9pbmdfYmVybGluLGFlcyh4ID0gc2Vhc29uLHkgPSBub3RfYXRfaG9tZV9jaGFuZ2UsZmlsbCA9IGxhbmRrcmVpcykpKw0KICBzdGF0X3N1bW1hcnlfYmluKGZ1biA9ICJtZWFuIiwNCiAgICAgICAgICAgICAgICAgICBnZW9tID0gImJhciIsDQogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSA1LHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkNCg0KZ2dwbG90bHkocGx0X2hpc3Rfc2Vhc29uKQ0KYGBgDQoNCg0KU28gaXQgc2VlbXMgdGhhdCBzZWFzb24gaGFzIGFuIGVub3Jtb3VzIGltcGFjdCBhdCBtb2JpbGl0eSBvZiBjaXRpemVucy4NCkFub3RoZXIgaW1wb3J0YW50IHBhcmFtZXRlciBjYW4gYmUgZGVzY3JpcHRpb24gb2YgdGhlIHdlYXRoZXIgYmFzZWQgb24gS2VsaGVpbSBzdGF0aXN0aWNzLCB3ZSB3aWxsIG1lcmdlIGl0IGludG8gSW5nb2xzdGFkdCB3ZWF0aGVyLCBiZWNhdXNlIG9mIHRoZSBhc3N1bXB0aW9uLCB0aGF0IEluZ29sc3RhZHQgYWQgS2VsaGVpbSBoYXZlIHRoZSBzaW1pbGFyIHdlYXRoZXIgcHJvcGVydGllcy4NCg0KYGBge3IgYWRkaW5nIGRlc2NyaXB0aW9uIHRvIGFuIGluZ29sc3RhZHQgZGF0YX0NCnR5cGVfb2Zfd2VhdGhlciA9IHVuaXF1ZSh3ZWF0aGVyc3RhY2tfa2VsaGVpbSRkZXNjcmlwdGlvbikNCg0Kd2VhdGhlcnN0YWNrX2tlbGhlaW1feWVhcl93ZWVrID0gd2VhdGhlcnN0YWNrX2tlbGhlaW0gJT4lIG11dGF0ZSh5ZWFyX3dlZWsgPSBwYXN0ZTAoaXNveWVhcihkYXRlKSwiLSIsaXNvd2VlayhkYXRlKSkpDQoNCndlZWtfZGVzY3JpcHRpb25faW1wYWN0ID0gd2VhdGhlcnN0YWNrX2tlbGhlaW1feWVhcl93ZWVrICU+JSBncm91cF9ieSh5ZWFyX3dlZWspICU+JSBjb3VudChkZXNjcmlwdGlvbikNCg0Kd2Vla19kZXNjcmlwdGlvbl9pbXBhY3QgPSB3ZWVrX2Rlc2NyaXB0aW9uX2ltcGFjdCAlPiUgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGRlc2NyaXB0aW9uLHZhbHVlc19mcm9tID0gbikNCg0KI3JlbW92ZSBOQXMNCndlZWtfZGVzY3JpcHRpb25faW1wYWN0W2lzLm5hKHdlZWtfZGVzY3JpcHRpb25faW1wYWN0KV0gPSAwDQpwcmludCh3ZWVrX2Rlc2NyaXB0aW9uX2ltcGFjdCkNCmBgYA0KYGBge3Igam9pbiBpdCB3aXRoIG1vYmlsaXR5IGRhdGEgSW5nb2xzdGFkdH0NCm1vYl9qb2luZWRfd2l0aF9pbmdvbHN0YWR0X2Rlc2NyaXB0aW9uID0gbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHQgJT4lIGlubmVyX2pvaW4od2Vla19kZXNjcmlwdGlvbl9pbXBhY3QsIGJ5ID0gInllYXJfd2VlayIpDQojbm9ybWFsaXplIGl0IHRvIGEgcGVyY2VudGFnZQ0KbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb25bdHlwZV9vZl93ZWF0aGVyXSA9IG1vYl9qb2luZWRfd2l0aF9pbmdvbHN0YWR0X2Rlc2NyaXB0aW9uW3R5cGVfb2Zfd2VhdGhlcl0vMTY4ICMxNjggaG91cnMgYSB3ZWVrDQoNCiNBc3N1bXB0aW9uIG5vdF9hdF9ob21lX2NoYW5nZSBpcyBjYWxjdWxhdGVkIHRocm91Z2ggaW5kaXZpZHVhbCB3ZWF0aGVyIGltcGFjdCBub3JtYWxseQ0KIz0+IGVhY2ggdHlwZSBvZiB3ZWF0aGVyIGZvciB0aGUgd2VhayBnZXQgaXRzIG93biB3ZWF0aGVyIGltcGFjdCBiYXNlZCBvbiBub3RfYXRfaG9tZQ0KDQojbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb25bdHlwZV9vZl93ZWF0aGVyXSA9IG1vYl9qb2luZWRfd2l0aF9pbmdvbHN0YWR0X2Rlc2NyaXB0aW9uW3R5cGVfb2Zfd2VhdGhlcl0qbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb24kbm90X2F0X2hvbWVfY2hhbmdlDQoNCg0KcHJpbnQobW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb24pDQpgYGANCg0KDQpgYGB7ciBsZXRzIGJhcmNoYXJ0IGl0IDopfQ0KbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb25fbG9uZ2VyID0gbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb24lPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhbGxfb2YodHlwZV9vZl93ZWF0aGVyKSxuYW1lc190byA9ICJkZXNjcmlwdGlvbiIpDQoNCmRlc2NyaXB0aW9uX2ltcGFjdF9vdmVyYWxsID0gbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb25fbG9uZ2VyICU+JSANCiAgZ3JvdXBfYnkoZGVzY3JpcHRpb24pICU+JSBzdW1tYXJpemUoaW1wYWN0ID0gbWVhbih2YWx1ZSkpDQoNCnBsb3RfbHkoZGF0YSA9IGRlc2NyaXB0aW9uX2ltcGFjdF9vdmVyYWxsLHggPSB+ZGVzY3JpcHRpb24seSA9IH5pbXBhY3QsdHlwZT0gImJhciIpDQpgYGANCg0KIyMgKipUYWtlIGEgcG9saWN5IGRhdGEgaW50byB0YWJsZSoqDQojIyAqKlN0YXRpc2N0aWNhbCBldmFsdWF0aW9uIG9mIG51bGwgaHlwb3RoZXNpcywgaW5kZXBlbmRlbmN5IHRlc3RzKioNCiMjICoqU3RhcnRpbmcgd2l0aCBhIG1vZGVsKioNCg0KQWZ0ZXIgZmlyc3QgZGF0YSBwcmVwYXJhdGlvbiBhbmQgYW5hbHlzaXMsIGxldCdzIHRyeSB0byBtYWtlIHNvbWUgcHJlZGljaXRpb25zIGFib3V0IG5vdF9hdF9ob21lIGR1cmF0aW9uIGJhc2VkIG9uIHBsb3RzIHRoYXQgc2hvd24gdXMgYSBtYWpvciBpbXBhY3Qgb24gbm90X2F0X2hvbWUgdmFyaWFibGUsIGxpa2UgKnRhdmcqLCAqc2Vhc29uKiwgKmRlc2NyaXB0aW9uKiwgKnRhdmcqLiBTdGFydGluZyB3aXRoIGEgKmxpbmVhciBtb2RlbCogYW5kIHVzaW5nICpJbmdvbHN0YWR0IGRhdGEqIGxpbWl0ZWQgYnkgeWVhciAyMDIwLDIwMjENCg0KYGBge3IgbW9kZWxyfQ0KbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb24gPSBtb2Jfam9pbmVkX3dpdGhfaW5nb2xzdGFkdF9kZXNjcmlwdGlvbiAlPiUgDQogIG11dGF0ZShzZWFzb24gPSBpZmVsc2UobW9udGgoZGF0ZSkgJWluJSBjKDEyLDEsMiksIndpbnRlciIsTkEpKSAlPiUNCiAgbXV0YXRlKHNlYXNvbiA9IGlmZWxzZShtb250aChkYXRlKSAlaW4lIGMoMyw0LDUpLCJzcHJpbmciLHNlYXNvbikpICU+JQ0KICBtdXRhdGUoc2Vhc29uID0gaWZlbHNlKG1vbnRoKGRhdGUpICVpbiUgYyg2LDcsOCksInN1bW1lciIsc2Vhc29uKSkgJT4lDQogIG11dGF0ZShzZWFzb24gPSBpZmVsc2UobW9udGgoZGF0ZSkgJWluJSBjKDksMTAsMTEpLCJhdXR1bW4iLHNlYXNvbikpDQoNCnRyYWluX2RhdGEgPSBtb2Jfam9pbmVkX3dpdGhfaW5nb2xzdGFkdF9kZXNjcmlwdGlvbiAlPiUgZmlsdGVyKHllYXIoZGF0ZSk8MjAyMikNCg0KZmlyc3RfbW9kZWwgPSBsbShub3RfYXRfaG9tZV9jaGFuZ2UgfiBzZWFzb24qcHJjcF93ZWVrKnRhdmcsDQogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhKQ0KDQpgYGANCg0KYGBge3IgcHJlZGljdGlvbnN9DQoNCg0KdGVzdF9kYXRhID0gbW9iX2pvaW5lZF93aXRoX2luZ29sc3RhZHRfZGVzY3JpcHRpb24gJT4lIGFkZF9wcmVkaWN0aW9ucyhtb2RlbCA9IGZpcnN0X21vZGVsKSAlPiUgYWRkX3Jlc2lkdWFscyhtb2RlbCA9IGZpcnN0X21vZGVsKQ0KDQpnZ3Bsb3QodGVzdF9kYXRhKSArDQogIGdlb21fbGluZShhZXMoeCA9IGRhdGUseSA9IG5vdF9hdF9ob21lX2NoYW5nZSxjb2xvciA9IGMoImJsdWUiKSkpKw0KICBnZW9tX2xpbmUoYWVzKHggPSBkYXRlLHkgPSBwcmVkLGNvbG9yID0gInJlZCIpKQ0KDQpgYGANCg0KDQo=